<template>
  <div class="file-manager-container">
    <div class="toolbar">
      <el-button v-hasPermi="['production:projectFolder:add']" v-show="currentPath.length === 1" type="primary"
        icon="el-icon-folder-add" @click="showAddFolder = true">新增文件夹</el-button>
      <el-button v-show="currentPath.length > 1" icon="el-icon-back" @click="goBack">返回上一级</el-button>
      <el-button v-hasPermi="['production:projectFolder:remove']" v-show="selectedItem" type="danger"
        icon="el-icon-delete" @click="deleteSelected">删除选中项</el-button>
      <!-- 新增重命名按钮，仅选中文件夹时显示 -->
      <el-button v-hasPermi="['production:projectFolder:edit']" v-show="selectedItem && selectedItem.type === 'folder'"
        icon="el-icon-edit" @click="openRenameDialog">重命名</el-button>
      <el-button v-hasPermi="['production:projectFileInfo:add']" v-show="showUploadFileBtn && currentPath.length > 1"
        icon="el-icon-upload" @click="showUploadFile = true">上传文件</el-button>
      <el-button v-hasPermi="['production:projectFileInfo:remove']" v-show="selectedFile" type="danger"
        icon="el-icon-delete" @click="handleDeleteFile" style="margin-left:8px;">删除文件</el-button>
      <el-button v-if="selectedFile" icon="el-icon-info" @click="handleFileDetail"
        style="margin-left:8px;">详情</el-button>
      <span class="breadcrumb">
        <span v-for="(folder, idx) in currentPath" :key="idx">
          <span v-if="idx !== 0"> / </span>{{ folder }}
        </span>
      </span>
      <!-- 文件名搜索框和按钮，仅在进入文件夹时显示 -->
      <div v-if="currentPath.length > 1" style="display: flex; align-items: center; margin-left: 16px;">
        <el-input v-model="searchFileNameInput" placeholder="搜索文件名" clearable style="width: 200px;"
          @keyup.enter="handleSearchFileName" />
        <el-button type="primary" icon="el-icon-search" style="margin-left: 8px;"
          @click="handleSearchFileName">搜索</el-button>
      </div>
    </div>
    <!-- 文件夹列表优化：根目录和子目录分别处理 -->
    <div v-if="currentPath.length === 1">
      <div v-if="currentFolder && currentFolder.children && currentFolder.children.length > 0" class="file-list">
        <div v-for="item in pagedFolders" :key="item.id" class="file-item"
          :class="{ selected: selectedItem && selectedItem.id === item.id }" @click="handleSelect(item)"
          @dblclick="handleDblClick(item)">
          <span v-if="item.type === 'folder'">
            <svg class="file-icon" viewBox="0 0 64 64">
              <rect x="4" y="20" width="56" height="36" rx="8" fill="#b2cfff" />
              <rect x="4" y="12" width="28" height="16" rx="6" fill="#8bb7f0" />
            </svg>
          </span>
          <span v-else-if="item.type === 'excel'">
            <svg class="file-icon" viewBox="0 0 64 64">
              <rect x="8" y="8" width="48" height="48" rx="8" fill="#e8f5e9" />
              <rect x="16" y="16" width="32" height="32" rx="4" fill="#43a047" />
              <text x="32" y="44" text-anchor="middle" font-size="22" fill="#fff" font-family="Arial">X</text>
            </svg>
          </span>
          <span v-else-if="item.type === 'word'">
            <svg class="file-icon" viewBox="0 0 64 64">
              <rect x="8" y="8" width="48" height="48" rx="8" fill="#e3eafd" />
              <rect x="16" y="16" width="32" height="32" rx="4" fill="#1976d2" />
              <text x="32" y="44" text-anchor="middle" font-size="22" fill="#fff" font-family="Arial">W</text>
            </svg>
          </span>
          <span v-else-if="item.type === 'video'">
            <svg class="file-icon" viewBox="0 0 64 64">
              <rect x="8" y="8" width="48" height="48" rx="8" fill="#e1f5fe" />
              <rect x="16" y="16" width="32" height="32" rx="4" fill="#039be5" />
              <polygon points="26,24 40,32 26,40" fill="#fff" />
            </svg>
          </span>
          <div class="file-name">{{ item.name }}</div>
        </div>
      </div>
      <div v-else class="empty-tip">
        暂无文件夹
      </div>
      <el-pagination v-if="currentFolder && currentFolder.children && currentFolder.children.length > 0"
        :current-page="folderPageNum" :page-size="folderPageSize" :total="currentFolder.children.length"
        layout="total, prev, pager, next, sizes" @current-change="val => folderPageNum = val"
        @size-change="val => { folderPageSize = val; folderPageNum = 1; }" :page-sizes="[5, 10, 20, 50]"
        style="margin-top: 10px; text-align: right;" />
    </div>
    <div v-else>
      <div v-if="currentFolder && currentFolder.children && currentFolder.children.length > 0" class="file-list">
        <div v-for="item in pagedFolders" :key="item.id" class="file-item"
          :class="{ selected: selectedItem && selectedItem.id === item.id }" @click="handleSelect(item)"
          @dblclick="handleDblClick(item)">
          <span v-if="item.type === 'folder'">
            <svg class="file-icon" viewBox="0 0 64 64">
              <rect x="4" y="20" width="56" height="36" rx="8" fill="#b2cfff" />
              <rect x="4" y="12" width="28" height="16" rx="6" fill="#8bb7f0" />
            </svg>
          </span>
          <span v-else-if="item.type === 'excel'">
            <svg class="file-icon" viewBox="0 0 64 64">
              <rect x="8" y="8" width="48" height="48" rx="8" fill="#e8f5e9" />
              <rect x="16" y="16" width="32" height="32" rx="4" fill="#43a047" />
              <text x="32" y="44" text-anchor="middle" font-size="22" fill="#fff" font-family="Arial">X</text>
            </svg>
          </span>
          <span v-else-if="item.type === 'word'">
            <svg class="file-icon" viewBox="0 0 64 64">
              <rect x="8" y="8" width="48" height="48" rx="8" fill="#e3eafd" />
              <rect x="16" y="16" width="32" height="32" rx="4" fill="#1976d2" />
              <text x="32" y="44" text-anchor="middle" font-size="22" fill="#fff" font-family="Arial">W</text>
            </svg>
          </span>
          <span v-else-if="item.type === 'video'">
            <svg class="file-icon" viewBox="0 0 64 64">
              <rect x="8" y="8" width="48" height="48" rx="8" fill="#e1f5fe" />
              <rect x="16" y="16" width="32" height="32" rx="4" fill="#039be5" />
              <polygon points="26,24 40,32 26,40" fill="#fff" />
            </svg>
          </span>
          <div class="file-name">{{ item.name }}</div>
        </div>
      </div>
      <el-pagination v-if="currentFolder && currentFolder.children && currentFolder.children.length > 0"
        :current-page="folderPageNum" :page-size="folderPageSize" :total="currentFolder.children.length"
        layout="total, prev, pager, next, sizes" @current-change="val => folderPageNum = val"
        @size-change="val => { folderPageSize = val; folderPageNum = 1; }" :page-sizes="[5, 10, 20, 50]"
        style="margin-top: 10px; text-align: right;" />
    </div>
    <!-- 新建文件夹弹窗 -->
    <el-dialog title="新建文件夹" :visible.sync="showAddFolder" width="300px" @close="newFolderName = ''">
      <el-input v-model="newFolderName" placeholder="输入文件夹名称"></el-input>
      <span slot="footer" class="dialog-footer">
        <el-button @click="showAddFolder = false">取消</el-button>
        <el-button type="primary" @click="addFolder">确定</el-button>
      </span>
    </el-dialog>
    <!-- 新增重命名弹窗 -->
    <el-dialog title="重命名文件夹" :visible.sync="showRenameFolder" width="300px" @close="renameFolderName = ''">
      <el-input v-model="renameFolderName" placeholder="输入新文件夹名称"></el-input>
      <span slot="footer" class="dialog-footer">
        <el-button @click="showRenameFolder = false">取消</el-button>
        <el-button type="primary" @click="renameFolder">确定</el-button>
      </span>
    </el-dialog>
    <!-- 新增上传文件弹窗 -->
    <el-dialog title="上传文件" :visible.sync="showUploadFile" width="400px" @close="uploadFiles = []">
      <el-upload action="" :auto-upload="false" multiple :file-list="uploadFiles" :on-change="handleFileChange"
        :before-upload="beforeUpload" :show-file-list="true" :on-remove="handleFileRemove" drag>
        <i class="el-icon-upload"></i>
        <div class="el-upload__text">将文件拖到此处，或<em>点击上传</em></div>
        <div v-if="fileType === 12 || fileType === '12'" class="upload-tip-image-only">仅支持图片类型文件</div>
        <div v-if="fileType === 21 || fileType === '21' || fileType === 22 || fileType === '22'"
          class="upload-tip-image-only">仅支持视频类型文件</div>
      </el-upload>

      <!-- 添加进度条显示 -->
      <div v-if="uploadProgress.show" class="upload-progress-container">
        <div class="upload-progress-header">
          <span>上传进度</span>
          <span class="upload-progress-text">{{ uploadProgress.current }}/{{ uploadProgress.total }}</span>
        </div>
        <el-progress :percentage="uploadProgress.percentage" :status="uploadProgress.status" :stroke-width="8"
          :show-text="false" />
        <div class="upload-progress-info">
          <span v-if="uploadProgress.currentFile" class="current-file">{{ uploadProgress.currentFile }}</span>
          <span v-if="uploadProgress.status === 'success'" class="upload-success">✓ 上传完成</span>
          <span v-else-if="uploadProgress.status === 'exception'" class="upload-error">✗ 上传失败</span>
          <span v-else class="uploading-text">正在上传...</span>
        </div>
      </div>

      <span slot="footer" class="dialog-footer">
        <el-button @click="showUploadFile = false" :disabled="uploadProgress.show">取消</el-button>
        <el-button type="primary" @click="submitUpload" :loading="uploadProgress.show"
          :disabled="uploadProgress.show">上传</el-button>
      </span>
    </el-dialog>
    <!-- 在文件列表下方展示当前文件夹下的文件 -->
    <div v-if="currentPath.length > 1">
      <div v-if="filteredFiles.length > 0" class="project-file-list">
        <div class="project-file-item" v-for="file in pagedFiles" :key="file.id"
          :class="{ selected: selectedFile && selectedFile.id === file.id }" @click="handleFileClick(file)">
          <span v-if="getFileIconType(file.fileName) === 'word'">
            <svg class="file-icon" viewBox="0 0 64 64">
              <rect x="8" y="8" width="48" height="48" rx="8" fill="#e3eafd" />
              <rect x="16" y="16" width="32" height="32" rx="4" fill="#1976d2" />
              <text x="32" y="44" text-anchor="middle" font-size="22" fill="#fff" font-family="Arial">W</text>
            </svg>
          </span>
          <span v-else-if="getFileIconType(file.fileName) === 'excel'">
            <svg class="file-icon" viewBox="0 0 64 64">
              <rect x="8" y="8" width="48" height="48" rx="8" fill="#e8f5e9" />
              <rect x="16" y="16" width="32" height="32" rx="4" fill="#43a047" />
              <text x="32" y="44" text-anchor="middle" font-size="22" fill="#fff" font-family="Arial">X</text>
            </svg>
          </span>
          <span v-else-if="getFileIconType(file.fileName) === 'ppt'">
            <svg class="file-icon" viewBox="0 0 64 64">
              <rect x="8" y="8" width="48" height="48" rx="8" fill="#ffe5d0" />
              <rect x="16" y="16" width="32" height="32" rx="4" fill="#ff9800" />
              <text x="32" y="44" text-anchor="middle" font-size="22" fill="#fff" font-family="Arial">P</text>
            </svg>
          </span>
          <span v-else-if="getFileIconType(file.fileName) === 'pdf'">
            <svg class="file-icon" viewBox="0 0 64 64">
              <rect x="8" y="8" width="48" height="48" rx="8" fill="#ffeaea" />
              <rect x="16" y="16" width="32" height="32" rx="4" fill="#e53935" />
              <text x="32" y="44" text-anchor="middle" font-size="22" fill="#fff" font-family="Arial">PDF</text>
            </svg>
          </span>
          <span v-else-if="getFileIconType(file.fileName) === 'image'">
            <svg class="file-icon" viewBox="0 0 64 64" @click.stop="handlePreview(file)" style="cursor:pointer;"
              title="点击预览图片">
              <rect x="8" y="8" width="48" height="48" rx="8" fill="#e0f7fa" />
              <rect x="16" y="16" width="32" height="32" rx="4" fill="#00bcd4" />
              <circle cx="32" cy="36" r="8" fill="#fff" />
            </svg>
          </span>
          <span v-else-if="getFileIconType(file.fileName) === 'txt'">
            <svg class="file-icon" viewBox="0 0 64 64">
              <rect x="8" y="8" width="48" height="48" rx="8" fill="#f5f5f5" />
              <rect x="16" y="16" width="32" height="32" rx="4" fill="#888" />
              <text x="32" y="44" text-anchor="middle" font-size="22" fill="#fff" font-family="Arial">TXT</text>
            </svg>
          </span>
          <span v-else-if="getFileIconType(file.fileName) === 'zip'">
            <svg class="file-icon" viewBox="0 0 64 64">
              <rect x="8" y="8" width="48" height="48" rx="8" fill="#fffde7" />
              <rect x="16" y="16" width="32" height="32" rx="4" fill="#fbc02d" />
              <text x="32" y="44" text-anchor="middle" font-size="22" fill="#fff" font-family="Arial">ZIP</text>
            </svg>
          </span>
          <span v-else-if="getFileIconType(file.fileName) === 'video'">
            <svg class="file-icon" viewBox="0 0 64 64">
              <rect x="8" y="8" width="48" height="48" rx="8" fill="#e1f5fe" />
              <rect x="16" y="16" width="32" height="32" rx="4" fill="#039be5" />
              <polygon points="26,24 40,32 26,40" fill="#fff" />
            </svg>
          </span>
          <span v-else>
            <svg class="file-icon" viewBox="0 0 64 64">
              <rect x="8" y="8" width="48" height="48" rx="8" fill="#f5f5f5" />
              <rect x="16" y="16" width="32" height="32" rx="4" fill="#888" />
              <text x="32" y="44" text-anchor="middle" font-size="22" fill="#fff" font-family="Arial">F</text>
            </svg>
          </span>
          <span class="file-name">{{ file.fileName }}</span>
          <div class="file-actions">
            <el-link type="primary" @click="handlePreview(file)">预览</el-link>
            <el-link @click="handleDownload(file)" v-if="file.downloadUrl">下载</el-link>
          </div>
        </div>
      </div>
      <div v-else class="empty-tip" style="margin-top: 16px;">
        暂无文件
      </div>
      <el-pagination v-if="filteredFiles.length > 0" :current-page="filePageNum" :page-size="filePageSize"
        :total="filteredFiles.length" layout="total, prev, pager, next, sizes"
        @current-change="val => filePageNum = val" @size-change="val => { filePageSize = val; filePageNum = 1; }"
        :page-sizes="[5, 10, 20, 50]" style="margin-top: 10px; text-align: right;" />
    </div>
    <!-- 在文件列表下方展示当前文件夹下的文件 -->
    <el-dialog :visible.sync="previewDialogVisible" width="60vw" top="5vh" :title="getPreviewTitle()"
      @close="previewFile = null">
      <div v-if="previewFile">
        <!-- 图片预览 - 使用Element UI的图片预览功能 -->
        <el-image v-if="getFileIconType(previewFile.fileName) === 'image'" :src="previewFile.downloadUrl"
          :preview-src-list="previewFile.imageUrls || [previewFile.downloadUrl]" fit="contain"
          style="max-width:100%;max-height:70vh;display:block;margin:auto;cursor:pointer;"
          :initial-index="previewFile.currentImageIndex || 0">
          <div slot="error" class="image-slot">
            <i class="el-icon-picture-outline"></i>
          </div>
        </el-image>
        <!-- 视频预览 -->
        <video v-else-if="getFileIconType(previewFile.fileName) === 'video'" :src="previewFile.downloadUrl"
          style="max-width:100%;max-height:70vh;display:block;margin:auto;" controls></video>
        <!-- 文档/PDF/PPT/Word/Excel 预览：直接用iframe打开 -->
        <iframe v-else-if="['pdf', 'word', 'excel', 'ppt'].includes(getFileIconType(previewFile.fileName))"
          :src="previewFile.downloadUrl" style="width:100%;height:70vh;border:none;"></iframe>
        <!-- 其他类型提示 -->
        <div v-else style="text-align:center;padding:40px 0;color:#888;">
          暂不支持该类型文件的在线预览，请下载后查看。
        </div>
      </div>
    </el-dialog>

    <!-- 隐藏的图片预览组件，用于直接触发预览 -->
    <el-image v-if="previewFile && getFileIconType(previewFile.fileName) === 'image'" ref="hiddenImagePreview"
      :key="`preview-${previewFile.id}`" :src="previewFile.downloadUrl"
      :preview-src-list="previewFile.imageUrls || [previewFile.downloadUrl]" :initial-index="0" style="display: none;">
    </el-image>

    <el-dialog :visible.sync="detailDialogVisible" width="700px" :show-close="true" append-to-body
      class="daily-detail-dialog">
      <div class="daily-detail-title">文件详情</div>

      <div class="daily-section-title">基本信息</div>
      <div class="daily-row-flex">
        <div class="daily-col-flex">
          <table class="daily-detail-table">
            <tr>
              <th class="left-align">文件名</th>
              <td class="value">{{ detailFileInfo && detailFileInfo.fileName }}</td>
            </tr>
            <tr>
              <th class="left-align">文件类型</th>
              <td class="value">{{ detailFileInfo && detailFileInfo.fileType }}</td>
            </tr>
            <tr>
              <th class="left-align">文件大小</th>
              <td class="value">{{ detailFileInfo && detailFileInfo.fileSize }}</td>
            </tr>
            <tr>
              <th class="left-align">上传人</th>
              <td class="value">{{ detailFileInfo && detailFileInfo.createBy }}</td>
            </tr>
            <tr>
              <th class="left-align">上传时间</th>
              <td class="value">{{ detailFileInfo && changeTime(detailFileInfo.createTime) }}</td>
            </tr>
          </table>
        </div>
      </div>
      <span slot="footer" class="dialog-footer">
        <el-button @click="detailDialogVisible = false" type="primary" plain>关闭</el-button>
      </span>
    </el-dialog>
  </div>
</template>

<script>
import { addProjectFolder, listProjectFolder, delProjectFolder, updateProjectFolder } from "@/api/production/projectFolder";
import { addProjectFolder2, listProjectFolder2, delProjectFolder2, updateProjectFolder2, listProjectFileInfo2, delProjectFileInfo2, addProjectFileInfo2 } from "@/api/production/companyNoticeFolder";
import { addProjectFileInfoByFile, listProjectFileInfo, delProjectFileInfo, fileLinkTransfer, fileLinkLooking } from "@/api/production/projectFileInfo";
import { getProjectFileInfo } from "@/api/production/projectFileInfo";
export default {
  name: "MacosFileManager",
  props: {
    projectId: {
      type: [String, Number],
      required: false,
      default: null
    },
    fileType: {
      type: [String, Number],
      required: false,
      default: null
    },
    folderName: {
      type: String,
      default: ''
    },
    initialData: {
      type: Object,
      default: () => ({
        id: '_' + Math.random().toString(36).substr(2, 9),
        name: '根目录',
        type: 'folder',
        children: [
          {
            id: '_' + Math.random().toString(36).substr(2, 9),
            name: '项目文档',
            type: 'folder',
            children: [
              { id: '_' + Math.random().toString(36).substr(2, 9), name: '需求说明.docx', type: 'word' },
              { id: '_' + Math.random().toString(36).substr(2, 9), name: '预算表.xlsx', type: 'excel' }
            ]
          },
          // {
          //   id: '_' + Math.random().toString(36).substr(2, 9),
          //   name: '财务报表.xlsx',
          //   type: 'excel'
          // },
          // {
          //   id: '_' + Math.random().toString(36).substr(2, 9),
          //   name: '会议纪要.docx',
          //   type: 'word'
          // }
        ]
      })
    }
  },
  data() {
    return {
      root: null,
      currentPath: ['根目录'],
      currentFolder: null,
      showAddFolder: false,
      newFolderName: '',
      selectedItem: null,
      // 新增重命名相关状态
      showRenameFolder: false,
      renameFolderName: '',
      // 新增上传相关状态
      showUploadFile: false,
      uploadFiles: [],
      showUploadFileBtn: false,
      fileList: [], // 当前文件夹下的文件列表
      selectedFile: null, // 选中的文件
      previewDialogVisible: false,
      previewFile: null,
      // 文件夹分页
      folderPageNum: 1,
      folderPageSize: 20,
      // 文件分页
      filePageNum: 1,
      filePageSize: 20,
      // 文件详情弹窗
      detailDialogVisible: false,
      detailFileInfo: null,
      searchFileName: '', // 实际用于过滤的关键字
      searchFileNameInput: '', // 输入框内容
      // 新增上传进度条状态
      uploadProgress: {
        show: false,
        current: 0,
        total: 0,
        percentage: 0,
        status: '', // 'success', 'exception', ''
        currentFile: '',
      },
    }
  },
  mounted() {
    this.fetchFolderData();
  },
  computed: {
    pagedFolders() {
      if (!this.currentFolder || !this.currentFolder.children) return [];
      const start = (this.folderPageNum - 1) * this.folderPageSize;
      return this.currentFolder.children.slice(start, start + this.folderPageSize);
    },
    // 过滤后的文件列表
    filteredFiles() {
      if (!this.searchFileName) return this.fileList;
      return this.fileList.filter(file =>
        file.fileName && file.fileName.toLowerCase().includes(this.searchFileName.toLowerCase())
      );
    },
    pagedFiles() {
      const start = (this.filePageNum - 1) * this.filePageSize;
      return this.filteredFiles.slice(start, start + this.filePageSize);
    }
  },
  watch: {
    projectId: 'fetchFolderData',
    fileType: 'fetchFolderData',
    folderName: 'fetchFolderData',
    // 切换文件夹或文件时重置分页
    'currentFolder'(val) {
      this.folderPageNum = 1;
    },
    'fileList'(val) {
      this.filePageNum = 1;
    },
  },
  methods: {
    changeTime(time) {
      if (!time) return '';
      const date = new Date(time);
      if (isNaN(date.getTime())) return time;
      const pad = n => n < 10 ? '0' + n : n;
      const y = date.getFullYear();
      const m = pad(date.getMonth() + 1);
      const d = pad(date.getDate());
      const h = pad(date.getHours());
      const min = pad(date.getMinutes());
      const s = pad(date.getSeconds());
      return `${y}-${m}-${d} ${h}:${min}:${s}`;
    },
    fetchFolderData() {
      if (this.fileType == 97) {
        if (!this.fileType) return;
      } else {
        if (!this.projectId || !this.fileType) return;
      }
      const apiMethod = this.fileType == 97 ? listProjectFolder2 : listProjectFolder;
      const params = this.fileType == 97 ? {
        fileType: this.fileType,
        folderName: this.folderName
      } : {
        projectId: this.projectId,
        fileType: this.fileType,
        folderName: this.folderName
      };
      apiMethod(params).then(res => {
        console.log(33, res);
        // 将 rows 映射为 type: 'folder'，children: []
        const folders = (res.rows || []).map(item => ({
          id: item.id,
          name: item.folderName,
          type: 'folder',
          children: []
        }));
        this.root = {
          id: 'root',
          name: '根目录',
          type: 'folder',
          children: folders
        };
        this.currentPath = ['根目录'];
        this.currentFolder = this.root;
        this.selectedItem = null;
        // 初始化上传按钮状态
        this.showUploadFileBtn = this.currentPath.length > 1;
        this.fetchCurrentFolderFiles();
      });
    },
    // 获取当前文件夹下的文件列表
    fetchCurrentFolderFiles() {
      const folder = this.currentFolder;
      if (!folder || !folder.id || folder.id === 'root') {
        this.fileList = [];
        return;
      }
      const apiMethods = this.fileType == 97 ? listProjectFileInfo2 : listProjectFileInfo;

      apiMethods({ folderId: folder.id }).then(res => {
        this.fileList = res.rows || [];
      });
    },
    handleSelect(item) {
      if (this.selectedItem && this.selectedItem.id === item.id) {
        this.selectedItem = null;
        this.selectedFile = null;
      } else {
        this.selectedItem = item;
        this.selectedFile = null;
      }
    },
    // 文件单击选中
    handleFileClick(file) {
      if (this.selectedFile && this.selectedFile.id === file.id) {
        this.selectedFile = null;
      } else {
        this.selectedFile = file;
      }
    },
    // 删除文件
    handleDeleteFile() {
      if (!this.selectedFile) return;
      this.$confirm('确定要删除该文件吗？', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        const delApi = this.fileType == 97 ? delProjectFileInfo2 : delProjectFileInfo;

        delApi(this.selectedFile.id).then(() => {
          this.$message.success('删除成功');
          this.selectedFile = null;
          this.fetchCurrentFolderFiles();
        }).catch(() => {
          this.$message.error('删除失败');
        });
      }).catch(() => { });
    },
    handleDblClick(item) {
      if (item.type === 'folder') {
        this.currentPath.push(item.name);
        this.currentFolder = item;
        this.selectedItem = null;
        // 进入文件夹后显示上传按钮
        this.showUploadFileBtn = true;
        this.fetchCurrentFolderFiles();
      }
    },
    goBack() {
      if (this.currentPath.length <= 1) return;
      this.currentPath.pop();
      // 重新定位currentFolder
      let folder = this.root;
      for (let i = 1; i < this.currentPath.length; i++) {
        folder = folder.children.find(
          c => c.type === 'folder' && c.name === this.currentPath[i]
        );
        if (!folder) break;
      }
      this.currentFolder = folder || this.root;
      this.selectedItem = null;
      // 返回上一级时隐藏上传按钮
      this.showUploadFileBtn = this.currentPath.length > 1;
      this.fetchCurrentFolderFiles();
    },
    addFolder() {
      // 只允许在根目录下新建文件夹
      if (this.currentPath.length !== 1) {
        this.$message.error('只能在根目录下新建文件夹');
        return;
      }
      console.log(2, this.currentFolder)
      if (!this.currentFolder && this.fileType != 97) {
        this.$message.error('当前没有可用的文件夹目录');
        return;
      }
      const name = this.newFolderName.trim();
      if (!name) {
        this.$message.error('文件夹名称不能为空');
        return;
      }
      // 检查重名
      if (this.currentFolder.children.some(c => c.type === 'folder' && c.name === name)) {
        this.$message.error('已存在同名文件夹');
        return;
      }
      // 调用接口新增文件夹
      const apiMethod = this.fileType == 97 ? addProjectFolder2 : addProjectFolder;
      const params = this.fileType == 97 ? {
        folderName: name,
        fileType: this.fileType
      } : {
        folderName: name,
        projectId: this.projectId,
        fileType: this.fileType
      };
      apiMethod(params).then(() => {
        this.$message.success('新建文件夹成功');
        this.showAddFolder = false;
        this.newFolderName = '';
        this.fetchFolderData();
      }).catch(() => {
        this.$message.error('新建文件夹失败');
      });
    },
    deleteSelected() {
      if (!this.selectedItem) return;
      // 只允许删除文件夹类型
      if (this.selectedItem.type !== 'folder') {
        this.$message.error('只能删除文件夹');
        return;
      }
      this.$confirm('确定要删除该文件夹吗？', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        const apiMethod = this.fileType == 97 ? delProjectFolder2 : delProjectFolder;
        apiMethod(this.selectedItem.id)
          .then(() => {
            this.$message.success('删除成功');
            this.fetchFolderData();
          })
          .catch(() => {
            this.$message.error('删除失败');
          });
      }).catch(() => { });
    },
    openRenameDialog() {
      if (!this.selectedItem || this.selectedItem.type !== 'folder') return;
      this.renameFolderName = this.selectedItem.name;
      this.showRenameFolder = true;
    },
    renameFolder() {
      const name = this.renameFolderName.trim();
      if (!name) {
        this.$message.error('文件夹名称不能为空');
        return;
      }
      // 检查重名（排除自己）
      if (this.currentFolder.children.some(c => c.type === 'folder' && c.name === name && c.id !== this.selectedItem.id)) {
        this.$message.error('已存在同名文件夹');
        return;
      }
      const apiMethod = this.fileType == 97 ? updateProjectFolder2 : updateProjectFolder;
      const params = this.fileType == 97 ? {
        id: this.selectedItem.id,
        folderName: name,
        fileType: this.fileType
      } : {
        id: this.selectedItem.id,
        folderName: name,
        projectId: this.projectId,
        fileType: this.fileType
      };
      apiMethod(params).then(() => {
        this.$message.success('重命名成功');
        this.showRenameFolder = false;
        this.renameFolderName = '';
        this.fetchFolderData();
      }).catch(() => {
        this.$message.error('重命名失败');
      });
    },
    // 上传相关方法
    handleFileChange(file, fileList) {
      // fileType为12时，只允许图片类型
      if (this.fileType === 12 || this.fileType === '12') {
        const imageExts = ["png", "jpg", "jpeg", "gif", "bmp", "svg", "webp"];
        // 过滤掉非图片类型
        const filtered = fileList.filter(f => {
          const ext = (f.name || f.raw?.name || '').split('.').pop().toLowerCase();
          return imageExts.includes(ext);
        });
        if (filtered.length < fileList.length) {
          this.$message.error('只能上传图片类型文件');
        }
        this.uploadFiles = filtered.map(f => f.raw || f);
      } else if (
        this.fileType === 21 || this.fileType === '21' ||
        this.fileType === 22 || this.fileType === '22'
      ) {
        const videoExts = ["mp4", "avi", "mov", "wmv", "flv", "mkv", "webm", "mpeg", "mpg"];
        const filtered = fileList.filter(f => {
          const ext = (f.name || f.raw?.name || '').split('.').pop().toLowerCase();
          return videoExts.includes(ext);
        });
        if (filtered.length < fileList.length) {
          this.$message.error('只能上传视频类型文件');
        }
        this.uploadFiles = filtered.map(f => f.raw || f);
      } else {
        this.uploadFiles = fileList.map(f => f.raw || f);
      }
    },
    beforeUpload(file) {
      // fileType为12时，只允许图片类型
      if (this.fileType === 12 || this.fileType === '12') {
        const ext = file.name.split('.').pop().toLowerCase();
        const imageExts = ["png", "jpg", "jpeg", "gif", "bmp", "svg", "webp"];
        if (!imageExts.includes(ext)) {
          this.$message.error('只能上传图片类型文件');
          return false;
        }
      }
      // fileType为21/22时，只允许视频类型
      if (
        this.fileType === 21 || this.fileType === '21' ||
        this.fileType === 22 || this.fileType === '22'
      ) {
        const ext = file.name.split('.').pop().toLowerCase();
        const videoExts = ["mp4", "avi", "mov", "wmv", "flv", "mkv", "webm", "mpeg", "mpg"];
        if (!videoExts.includes(ext)) {
          this.$message.error('只能上传视频类型文件');
          return false;
        }
      }
      // 阻止自动上传
      return false;
    },
    handleFileRemove(file, fileList) {
      this.uploadFiles = fileList.map(f => f.raw || f);
    },
    async submitUpload() {
      if (!this.uploadFiles || this.uploadFiles.length === 0) {
        this.$message.error('请选择文件');
        return;
      }
      const folder = this.currentFolder;
      this.uploadProgress.show = true;
      this.uploadProgress.current = 0;
      this.uploadProgress.total = this.uploadFiles.length;
      this.uploadProgress.percentage = 0;
      this.uploadProgress.status = '';
      this.uploadProgress.currentFile = '';

      try {
        const addFiles = this.fileType == 97 ? addProjectFileInfo2 : addProjectFileInfoByFile;

        // 模拟上传进度
        const simulateProgress = () => {
          return new Promise((resolve) => {
            let progress = 0;
            const interval = setInterval(() => {
              progress += Math.random() * 10 + 8; // 随机增加8-18%
              if (progress >= 90) { // 只模拟到90%，留10%给实际上传
                progress = 90;
                clearInterval(interval);
                resolve();
              }
              this.uploadProgress.percentage = Math.round(progress);
              this.uploadProgress.currentFile = this.uploadFiles[0]?.name || '';
            }, 150);
          });
        };

        // 先模拟进度到90%
        await simulateProgress();

        // 执行实际上传
        await addFiles({
          files: this.uploadFiles,
          folderId: folder && folder.id,
          fileType: this.fileType,
          projectId: this.projectId
        });

        // 上传完成，进度到100%
        this.uploadProgress.percentage = 100;
        this.uploadProgress.status = 'success';
        this.uploadProgress.currentFile = '上传完成';

        // 延迟一下显示成功消息
        setTimeout(() => {
          this.$message.success(`上传成功`);
          this.fetchCurrentFolderFiles();
          this.showUploadFile = false;
          this.uploadProgress.show = false;
          this.uploadFiles = [];
        }, 800);

      } catch (e) {
        this.$message.error('上传失败');
        this.uploadProgress.status = 'exception';
        this.uploadProgress.currentFile = '上传失败';

        // 延迟关闭进度条
        setTimeout(() => {
          this.uploadProgress.show = false;
        }, 2000);
      }
    },
    getFileIconType(fileName) {
      if (!fileName) return 'file';
      const ext = fileName.split('.').pop().toLowerCase();
      if (["doc", "docx"].includes(ext)) return "word";
      if (["xls", "xlsx"].includes(ext)) return "excel";
      if (["ppt", "pptx"].includes(ext)) return "ppt";
      if (["pdf"].includes(ext)) return "pdf";
      if (["png", "jpg", "jpeg", "gif", "bmp", "svg", "webp"].includes(ext)) return "image";
      if (["mp4", "avi", "mov", "wmv", "flv", "mkv", "webm", "mpeg", "mpg"].includes(ext)) return "video";
      if (["txt"].includes(ext)) return "txt";
      if (["zip", "rar", "7z", "tar", "gz"].includes(ext)) return "zip";
      return "file";
    },
    getFileIconSvg(fileName) {
      const type = this.getFileIconType(fileName);
      if (type === 'word') {
        return `<svg class='file-icon' viewBox='0 0 64 64'><rect x='8' y='8' width='48' height='48' rx='8' fill='#e3eafd'/><rect x='16' y='16' width='32' height='32' rx='4' fill='#1976d2'/><text x='32' y='44' text-anchor='middle' font-size='22' fill='#fff' font-family='Arial'>W</text></svg>`;
      }
      if (type === 'excel') {
        return `<svg class='file-icon' viewBox='0 0 64 64'><rect x='8' y='8' width='48' height='48' rx='8' fill='#e8f5e9'/><rect x='16' y='16' width='32' height='32' rx='4' fill='#43a047'/><text x='32' y='44' text-anchor='middle' font-size='22' fill='#fff' font-family='Arial'>X</text></svg>`;
      }
      if (type === 'ppt') {
        return `<svg class='file-icon' viewBox='0 0 64 64'><rect x='8' y='8' width='48' height='48' rx='8' fill='#ffe5d0'/><rect x='16' y='16' width='32' height='32' rx='4' fill='#ff9800'/><text x='32' y='44' text-anchor='middle' font-size='22' fill='#fff' font-family='Arial'>P</text></svg>`;
      }
      if (type === 'pdf') {
        return `<svg class='file-icon' viewBox='0 0 64 64'><rect x='8' y='8' width='48' height='48' rx='8' fill='#ffeaea'/><rect x='16' y='16' width='32' height='32' rx='4' fill='#e53935'/><text x='32' y='44' text-anchor='middle' font-size='22' fill='#fff' font-family='Arial'>PDF</text></svg>`;
      }
      if (type === 'image') {
        return `<svg class='file-icon' viewBox='0 0 64 64'><rect x='8' y='8' width='48' height='48' rx='8' fill='#e0f7fa'/><rect x='16' y='16' width='32' height='32' rx='4' fill='#00bcd4'/><circle cx='32' cy='36' r='8' fill='#fff'/></svg>`;
      }
      if (type === 'video') {
        return `<svg class='file-icon' viewBox='0 0 64 64'><rect x='8' y='8' width='48' height='48' rx='8' fill='#e1f5fe'/><rect x='16' y='16' width='32' height='32' rx='4' fill='#039be5'/><polygon points='26,24 40,32 26,40' fill='#fff'/></svg>`;
      }
      if (type === 'txt') {
        return `<svg class='file-icon' viewBox='0 0 64 64'><rect x='8' y='8' width='48' height='48' rx='8' fill='#f5f5f5'/><rect x='16' y='16' width='32' height='32' rx='4' fill='#888'/><text x='32' y='44' text-anchor='middle' font-size='22' fill='#fff' font-family='Arial'>TXT</text></svg>`;
      }
      if (type === 'zip') {
        return `<svg class='file-icon' viewBox='0 0 64 64'><rect x='8' y='8' width='48' height='48' rx='8' fill='#fffde7'/><rect x='16' y='16' width='32' height='32' rx='4' fill='#fbc02d'/><text x='32' y='44' text-anchor='middle' font-size='22' fill='#fff' font-family='Arial'>ZIP</text></svg>`;
      }
      // 默认文件
      return `<svg class='file-icon' viewBox='0 0 64 64'><rect x='8' y='8' width='48' height='48' rx='8' fill='#f5f5f5'/><rect x='16' y='16' width='32' height='32' rx='4' fill='#888'/><text x='32' y='44' text-anchor='middle' font-size='22' fill='#fff' font-family='Arial'>F</text></svg>`;
    },
    async handlePreview(file) {

      if (!file.downloadUrl) {
        this.$message.error('无效的预览链接');
        return;
      }
      try {
        let newUrl = '';
        console.log('预览 - 文件:', file);
        const type = this.getFileIconType(file.fileName);
        if (["image", "video"].includes(type)) {
          const res = await fileLinkTransfer(file.downloadUrl);
          newUrl = res.data.url;
        } else if (["pdf", "word", "excel", "ppt"].includes(type)) {
          const res = await fileLinkLooking(file.downloadUrl);
          newUrl = res.data.url;
          console.log('预览 - newUrl:', file, newUrl);
        } else {
          newUrl = file.downloadUrl;
        }
        if (!newUrl) {
          this.$message.error('获取预览链接失败');
          return;
        }

        // 如果是图片类型，直接触发Element UI的图片预览，不弹出弹框
        if (type === 'image') {
          // 只预览当前点击的图片，不收集其他图片
          this.previewFile = {
            ...file,
            downloadUrl: newUrl,
            imageUrls: [newUrl], // 只包含当前图片
            currentImageIndex: 0
          };

          // 使用$nextTick确保DOM更新后触发预览
          this.$nextTick(() => {
            // 通过ref直接触发图片预览
            if (this.$refs.hiddenImagePreview) {
              this.$refs.hiddenImagePreview.clickHandler();
            }
          });
        } else {
          // 非图片类型仍然使用弹框预览
          this.previewFile = { ...file, downloadUrl: newUrl };
          this.previewDialogVisible = true;
        }
      } catch (e) {
        this.$message.error('预览失败');
      }
    },
    async handleDownload(file) {
      if (!file.downloadUrl) {
        this.$message.error('无效的下载链接');
        return;
      }
      try {
        const res = await fileLinkTransfer(file.downloadUrl);
        // 假设接口返回 { url: '新下载链接' }
        const newUrl = res.data.url;
        if (!newUrl) {
          this.$message.error('获取下载链接失败');
          return;
        }
        // 创建a标签下载
        const a = document.createElement('a');
        a.href = newUrl;
        a.download = file.fileName || '';
        a.target = '_blank';
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
      } catch (e) {
        this.$message.error('下载失败');
      }
    },
    async handleFileDetail() {
      if (!this.selectedFile) return;
      try {
        const res = await getProjectFileInfo(this.selectedFile.id);
        this.detailFileInfo = res.data || res;
        this.detailDialogVisible = true;
      } catch (e) {
        this.$message.error('获取文件详情失败');
      }
    },
    getOfficePreviewUrl(url) {
      // 已废弃：直接用iframe打开word/excel
      return url || '';
    },
    handleSearchFileName() {
      this.searchFileName = this.searchFileNameInput;
      this.filePageNum = 1;
    },
    getPreviewTitle() {
      if (!this.previewFile) return '预览';
      const type = this.getFileIconType(this.previewFile.fileName);
      if (type === 'image' && this.previewFile.imageUrls && this.previewFile.imageUrls.length > 1) {
        const currentIndex = this.previewFile.currentImageIndex || 0;
        const total = this.previewFile.imageUrls.length;
        return `${this.previewFile.fileName} (${currentIndex + 1}/${total})`;
      }
      return this.previewFile.fileName;
    }
  }
}
</script>

<style lang="scss" scoped>
$main-bg: #fff;
$main-radius: 14px;
$main-shadow: 0 2px 16px rgba(0, 0, 0, 0.08);
$main-padding: 32px 40px 32px 40px;
$main-padding-mobile: 12px 2px;
$main-color: #333;
$main-muted: #888;
$main-hover: #f0f4ff;
$main-gap: 32px 36px;
$main-gap-mobile: 16px 8px;
$main-width: 900px;
$main-width-mobile: 100%;
$file-item-width: 110px;
$file-item-width-mobile: 80px;
$file-icon-size: 64px;
$file-icon-size-mobile: 44px;

body {
  width: 100%;
  height: 100%;
  background: #f7f8fa;
  margin: 0;
  font-family: 'San Francisco', 'PingFang SC', 'Microsoft YaHei', 'Roboto', sans-serif;
}

.file-manager-container {
  width: 100%;
  // margin: 20px 0; // 只保留上下间距
  background: $main-bg;
  // border-radius: $main-radius;
  // box-shadow: $main-shadow;
  padding: 20px 24px; // 两侧留点空隙
  min-height: 520px;
  position: relative;
  // border: 1px solid red;

  .toolbar {
    display: flex;
    align-items: center;
    margin-bottom: 24px;

    .el-button {
      margin-right: 12px;
    }

    .breadcrumb {
      margin-left: 16px;
      color: $main-muted;
      font-size: 1rem;
      user-select: none;
    }
  }

  .file-list {
    display: flex;
    flex-wrap: wrap;
    gap: $main-gap;
    margin-top: 16px;

    .file-item {
      width: $file-item-width;
      text-align: center;
      cursor: pointer;
      user-select: none;
      transition: background 0.2s;
      border-radius: 8px;
      padding: 12px 0 6px 0;

      &:hover {
        background: $main-hover;
      }

      .file-icon {
        width: $file-icon-size;
        height: $file-icon-size;
        margin-bottom: 8px;
        display: inline-block;
      }

      .file-name {
        font-size: 1rem;
        color: $main-color;
        word-break: break-all;
      }
    }
  }
}

@media (max-width: 600px) {
  .file-manager-container {
    padding: $main-padding-mobile;
    max-width: $main-width-mobile;

    .file-list {
      gap: $main-gap-mobile;

      .file-item {
        width: $file-item-width-mobile;
        padding: 8px 0 4px 0;

        .file-icon {
          width: $file-icon-size-mobile;
          height: $file-icon-size-mobile;
        }
      }
    }
  }
}

.file-item.selected {
  border: 2px solid #409EFF;
  background: #e6f7ff;
}

// 选中文件高亮
.project-file-item.selected {
  border: 2px solid #e6f7ff;
  background: #e6f7ff;
}

// 样式：让文件列表横向排列
.project-file-list {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  gap: 32px 24px;
  margin-top: 16px;
}

.project-file-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 110px;
  text-align: center;
  padding: 12px 0 6px 0;
  border-radius: 8px;
  background: #fff;
  transition: background 0.2s;
}

.project-file-item:hover {
  background: #f0f4ff;
}

.project-file-item .file-icon {
  width: 64px;
  height: 64px;
  margin-bottom: 8px;
  display: inline-block;
  transition: transform 0.2s ease;
}

.project-file-item .file-icon:hover {
  transform: scale(1.05);
}

.project-file-item .file-name {
  font-size: 1rem;
  color: #333;
  word-break: break-all;
  margin-bottom: 4px;
}

// 样式优化：让操作按钮一行显示
.file-actions {
  display: flex;
  flex-direction: row;
  gap: 8px;
  justify-content: center;
  margin-top: 4px;
}

// 上传弹窗图片类型提示样式
.upload-tip-image-only {
  color: #f56c6c;
  font-size: 13px;
  margin-top: 4px;
}

// 上传进度条样式
.upload-progress-container {
  margin-top: 20px;
  padding: 15px;
  background-color: #f8f9fa;
  border-radius: 8px;
  border: 1px solid #e9ecef;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}

.upload-progress-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 12px;
  font-size: 14px;
  color: #495057;
}

.upload-progress-text {
  font-weight: bold;
  color: #409EFF;
  background-color: #e6f7ff;
  padding: 2px 8px;
  border-radius: 12px;
  font-size: 12px;
}

.upload-progress-info {
  font-size: 13px;
  color: #6c757d;
  margin-top: 8px;
  display: flex;
  align-items: center;
  gap: 8px;
}

.current-file {
  color: #495057;
  font-weight: 500;
  max-width: 200px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.uploading-text {
  color: #409EFF;
  font-weight: 500;
}

.upload-success {
  color: #67c23a;
  font-weight: 500;
}

.upload-error {
  color: #f56c6c;
  font-weight: 500;
}

.daily-detail-dialog .el-dialog__body {
  background: #f4f6fb;
  padding: 0;
}

.daily-detail-title {
  font-size: 28px;
  font-weight: bold;
  color: #2d3a4b;
  margin-bottom: 36px;
  text-align: center;
  letter-spacing: 2px;
}

.daily-section-title {
  font-size: 18px;
  color: #4a90e2;
  font-weight: bold;
  margin: 32px 0 16px 0;
  border-left: 4px solid #4a90e2;
  padding-left: 12px;
  letter-spacing: 1px;
}

.daily-row-flex {
  display: flex;
  gap: 32px;
  margin-bottom: 12px;
}

.daily-col-flex {
  flex: 1;
}

.daily-detail-table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  background: none;
}

.daily-detail-table th,
.daily-detail-table td {
  padding: 10px 8px;
  font-size: 16px;
  border-bottom: 1px solid #f0f0f0;
}

.daily-detail-table th {
  width: 120px;
  color: #6b7a90;
  background: none;
  font-weight: normal;
  text-align: right;
  vertical-align: top;
  padding-right: 12px;
}

.daily-detail-table td.value {
  color: #222;
  text-align: left;
  font-weight: 500;
}

.daily-detail-table tr:last-child td,
.daily-detail-table tr:last-child th {
  border-bottom: none;
}

.icon {
  display: inline-block;
  width: 18px;
  height: 18px;
  vertical-align: middle;
  margin-right: 6px;
  opacity: 0.7;
}

.daily-detail-table th.left-align {
  text-align: center;
  padding-left: 0;
  padding-right: 0;
  background: #f7fafd;
}

.daily-detail-table th.center-bg {
  text-align: center;
  vertical-align: middle;
  background: #f7fafd;
  width: 180px;
}

@media (max-width: 900px) {
  .daily-row-flex {
    flex-direction: column;
    gap: 0;
  }
}

@media (max-width: 600px) {
  .daily-detail-title {
    font-size: 20px;
  }

  .daily-section-title {
    font-size: 15px;
    padding-left: 8px;
  }

  .daily-detail-table th,
  .daily-detail-table td {
    font-size: 13px;
    padding: 7px 4px;
  }
}

.empty-tip {
  width: 100%;
  text-align: center;
  color: #bbb;
  font-size: 16px;
  padding: 32px 0;
}

// 图片预览样式
.image-slot {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100%;
  height: 100%;
  color: #909399;
  font-size: 30px;
  background-color: #f5f7fa;
  border-radius: 4px;
}

// 图片预览弹窗样式优化
::v-deep .el-image-viewer__wrapper {
  z-index: 2100;
}

::v-deep .el-image-viewer__img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}

::v-deep .el-image-viewer__btn {
  background-color: rgba(0, 0, 0, 0.5);
  color: #fff;
  border-radius: 50%;
  width: 44px;
  height: 44px;
  line-height: 44px;
  font-size: 18px;
}

::v-deep .el-image-viewer__btn:hover {
  background-color: rgba(0, 0, 0, 0.7);
}

::v-deep .el-image-viewer__actions {
  background-color: rgba(0, 0, 0, 0.5);
  border-radius: 4px;
}

::v-deep .el-image-viewer__actions__inner {
  color: #fff;
}

::v-deep .el-image-viewer__actions__inner i {
  color: #fff;
  font-size: 16px;
}
</style>